package hzmg.akkacloud.server.web.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.hzmg.akkacloud.common.AkkaConstant;
import com.hzmg.akkacloud.common.response.ResultDTO;
import com.hzmg.akkacloud.common.utils.CommonUtils;
import com.hzmg.akkacloud.common.utils.NetUtils;
import hzmg.akkacloud.server.common.AkkaCloudServerConfigKey;
import hzmg.akkacloud.server.common.utils.PropertyUtils;
import hzmg.akkacloud.server.persistence.remote.model.AppInfoDO;
import hzmg.akkacloud.server.persistence.remote.repository.AppInfoRepository;
import hzmg.akkacloud.server.remote.transport.TransportService;
import hzmg.akkacloud.server.remote.worker.WorkerClusterQueryService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.Date;
import java.util.Optional;
import java.util.Properties;
import java.util.TimeZone;

/**
 * 处理Worker请求的 Controller
 * Worker启动时，先请求assert验证appName的可用性，再根据得到的appId获取Server地址
 * 计划修改成：Worker请求时直接携带信息进行注册，不再验证appName可用性，因为该步意味着需要手动注册，不符合注册中心功能
 *
 * @author zbw
 * @since 2022/7/23
 */
@RestController
@RequestMapping("/server")
@Slf4j
public class ServerController {

    @Resource
    private TransportService transportService;
    @Resource
    private AppInfoRepository appInfoRepository;
    @Resource
    private WorkerClusterQueryService workerClusterQueryService;


    @GetMapping("/register")
    public ResultDTO<Long> registerAppName(@RequestParam("appName") String appName) {
        Optional<AppInfoDO> appInfoOpt = appInfoRepository.findByAppName(appName);
        return appInfoOpt.map(appInfoDO -> ResultDTO.success(appInfoDO.getId())).
                orElseGet(() -> {
                    AppInfoDO appInfoDO = new AppInfoDO();
                    appInfoDO.setGmtCreate(new Date());
                    appInfoDO.setAppName(appName);
                    return ResultDTO.success(appInfoRepository.save(appInfoDO).getId());
                });
    }

    @GetMapping("/getPort")
    public ResultDTO<Integer> getPort(@RequestParam("appName") String appName) {
        Optional<AppInfoDO> appInfoOpt = appInfoRepository.findByAppName(appName);
        return appInfoOpt.map(appInfoDO -> {
            Properties properties = PropertyUtils.getProperties();
            int port = Integer.parseInt(properties.getProperty(AkkaCloudServerConfigKey.AKKA_PORT, String.valueOf(AkkaConstant.SERVER_DEFAULT_AKKA_PORT)));
            String portFromJVM = System.getProperty(AkkaCloudServerConfigKey.AKKA_PORT);
            if (StringUtils.isNotEmpty(portFromJVM)) {

                port = Integer.parseInt(portFromJVM);
            }
            return ResultDTO.success(port);

        }).orElseGet(() -> ResultDTO.failed("this appName is not register"));
    }


    @PostMapping("/hello")
    public ResultDTO<JSONObject> ping(@RequestParam(required = false) boolean debug) {
        JSONObject res = new JSONObject();
        res.put("localHost", NetUtils.getLocalHost());
        res.put("communicationSystemInfo", transportService.getProtocol2Transporter());
        res.put("serverTime", CommonUtils.formatTime(System.currentTimeMillis()));
        res.put("serverTimeZone", TimeZone.getDefault().getDisplayName());
        res.put("appIds", workerClusterQueryService.getAppId2ClusterStatus().keySet());
        if (debug) {
            res.put("appId2ClusterInfo", JSON.parseObject(JSON.toJSONString(workerClusterQueryService.getAppId2ClusterStatus())));

        }
        return ResultDTO.success(res);
    }

    @GetMapping("/test")
    public ResultDTO<String> test() {
        log.info("I am /server/test,I has been invoked");
        return ResultDTO.success("hello");
    }
}
